package web_api

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"platon-tools/go-service/common/constant"
	"platon-tools/go-service/common/util"
	go_logger "platon-tools/go-service/go-logger"
	"platon-tools/go-service/module"
	"platon-tools/go-service/module/model"
	"strconv"
	"time"
)

type Point struct {
	X interface{} `json:"x"`
	Y interface{} `json:"y"`
}

// 收益折线图
type BenefitLineChartResponse struct {
	DelegationReward []Point `json:"delegation_reward"` // 委托奖励折线图
	StakingReward    []Point `json:"staking_reward"`    // 质押奖励折线图
	FeeReward        []Point `json:"fee_reward"`        // 手续费奖励折线图
}

// 收益折线图
func (api *HttpApi) BenefitLineChart(c *gin.Context) {

	var err error

	userId, exist := c.Get("login_id")
	if !exist || userId == "" {
		c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1103, constant.ERROR_MESSAGE_1103))
		return
	}

	nodePrimaryId := c.Query("node_primary_id")
	if nodePrimaryId == "" {
		c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1103, constant.ERROR_MESSAGE_1103))
		return
	}

	daysStr := c.Query("days")
	if daysStr == "" {
		daysStr = "7"
	}

	days, err := strconv.Atoi(daysStr)
	if err != nil {
		c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1103, "days参数应为数字"))
		return
	}

	result := BenefitLineChartResponse{}

	r := api.service.ModuleByName("REDIS")
	if db, ok := r.(*module.RedisDB); ok {

		// 质押
		key := fmt.Sprintf("staking_reward_%s", nodePrimaryId)
		scores, values, err := db.ZRangeWithScores(key, 0, days-1)
		if err != nil {
			c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1001, constant.ERROR_MESSAGE_1001))
			return
		}
		result.StakingReward = GeneratePoints(scores, values)

		// 委托
		key = fmt.Sprintf("delegation_reward_%s", nodePrimaryId)
		scores, values, err = db.ZRangeWithScores(key, 0, days-1)
		if err != nil {
			c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1001, constant.ERROR_MESSAGE_1001))
			return
		}

		result.DelegationReward = GeneratePoints(scores, values)

		c.JSON(http.StatusOK, util.SuccessResponse(result))
		return
	}
}

// 生成points
func GeneratePoints(scores, values []string) []Point {
	result := make([]Point, 0)
	for i := 0; i < len(scores); i++ {
		score := scores[i]
		value := values[i]
		t, _ := time.ParseInLocation(constant.DATE_DAY_VALUE_FORMAT, score, constant.DEFAULT_LOCATION)
		x := t.Format(constant.DATE_DAY_FORMAT)
		y, _ := strconv.ParseFloat(value, 64)
		result = append(result, Point{x, y})
	}
	return result
}

// 委托人数量折线图
type LineChartResponse struct {
	ClientNum [][2]string `json:"client_num"` // 委托人数折线图
}

// 委托人数量折线图
func (api *HttpApi) ClientNumLineChart(c *gin.Context) {

	var err error

	userId, exist := c.Get("login_id")
	if !exist || userId == "" {
		c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1103, constant.ERROR_MESSAGE_1103))
		return
	}

	r := api.service.ModuleByName("MYSQLDB")
	if db, ok := r.(*module.MysqlDB); ok {
		var result StakingTotalResponse

		var nodes []*model.SysNode

		var user model.SysUser
		err = db.Table(model.SysUserTable).Where(map[string]interface{}{"id": userId}).Find(&user).Error
		if err != nil {
			go_logger.Logger.Error(err.Error())
			c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1001, constant.ERROR_MESSAGE_1001))
			return
		}

		var role model.SysRole
		err = db.Table(model.SysRoleTable).Where(map[string]interface{}{"id": user.RoleId}).Find(&role).Error
		if err != nil {
			go_logger.Logger.Error(err.Error())
			c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1001, constant.ERROR_MESSAGE_1001))
			return
		}

		selectDb := db.Table(model.SysNodeTable).Where(" id in (?)", role.GetNodePerm())
		err = selectDb.Find(&nodes).Error
		if err != nil {
			go_logger.Logger.Error(err.Error())
			c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1001, constant.ERROR_MESSAGE_1001))
			return
		}

		var staking, authorize, benefit float64
		//for _, node := range nodes {
		//	staking += node.Staking
		//	authorize += node.Authorize
		//	benefit += node.Benefit
		//}
		result.TotalStaking = fmt.Sprintf("%.2f", (staking))
		result.TotalAuthorize = fmt.Sprintf("%.2f", authorize)
		result.TotalBenefit = fmt.Sprintf("%.8f", benefit)

		c.JSON(http.StatusOK, util.SuccessResponse(result))
		return
	}
}

// 收益折线图
type FourEpochChartResponse struct {
	DelegationReward []string `json:"delegation_reward"` // 委托奖励折线图
	MiningReward     []string `json:"staking_reward"`    // 质押奖励折线图
	FeeReward        []string `json:"fee_reward"`        // 手续费奖励折线图
}

// 周期收益占比
func (api *HttpApi) CycleBenefit(c *gin.Context) {

	var err error

	userId, exist := c.Get("login_id")
	if !exist || userId == "" {
		c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1103, constant.ERROR_MESSAGE_1103))
		return
	}

	nodePrimaryId := c.Query("node_primary_id")
	if nodePrimaryId == "" {
		c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1103, constant.ERROR_MESSAGE_1103))
		return
	}

	result := FourEpochChartResponse{
		make([]string, 0),
		make([]string, 0),
		make([]string, 0),
	}

	r := api.service.ModuleByName("MYSQLDB")
	if db, ok := r.(*module.MysqlDB); ok {

		var nodeHistorys []*model.SysNodeContractHistory

		selectDb := db.Table(model.SysNodeContractHistoryTable).Where(" node_primary_id = ?", nodePrimaryId)
		err = selectDb.Limit(4).Order("create_time desc").Find(&nodeHistorys).Error
		if err != nil {
			go_logger.Logger.Error(err.Error())
			c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1001, constant.ERROR_MESSAGE_1001))
			return
		}

		for _, v := range nodeHistorys {
			result.DelegationReward = append(result.DelegationReward, fmt.Sprintf("%.2f", v.DelegationReward))
			result.MiningReward = append(result.MiningReward, fmt.Sprintf("%.2f", v.MiningReward))
		}

		c.JSON(http.StatusOK, util.SuccessResponse(result))
		return
	}
}

type FunnelItem struct {
	PledgeSum   string `json:"pledge_sum"`   // 总质押收益
	PledgeSelf  string `json:"pledge_self"`  // 自有质押收益
	PledgeOther string `json:"pledge_other"` // 接受委托收益
}

// 收益饼图
func (api *HttpApi) FunnelChart(c *gin.Context) {

	var err error

	userId, exist := c.Get("login_id")
	if !exist || userId == "" {
		c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1103, constant.ERROR_MESSAGE_1103))
		return
	}

	nodePrimaryId := c.Query("node_primary_id")
	if nodePrimaryId == "" {
		c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1103, constant.ERROR_MESSAGE_1103))
		return
	}

	r := api.service.ModuleByName("MYSQLDB")
	if db, ok := r.(*module.MysqlDB); ok {
		var result FunnelItem

		var node model.SysNodeContract

		selectDb := db.Table(model.SysNodeContractTable).Where(" node_primary_id = ?", nodePrimaryId)
		err = selectDb.Find(&node).Error
		if err != nil {
			go_logger.Logger.Error(err.Error())
			c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1001, constant.ERROR_MESSAGE_1001))
			return
		}

		result.PledgeSum = fmt.Sprintf("%.8f", node.StakingReward)
		result.PledgeOther = fmt.Sprintf("%.8f", node.DelegationReward)
		result.PledgeSelf = fmt.Sprintf("%.8f", node.StakingReward-node.DelegationReward)

		c.JSON(http.StatusOK, util.SuccessResponse(result))
		return
	}
}

type NodeInvest struct {
	NodeId     string  `json:"node_id"`     // 节点ID-地址
	NodeName   string  `json:"node_name"`   // 节点名称
	NodeInvest float64 `json:"node_invest"` // 节点投资量
}

// 所有节点投资分布
func (api *HttpApi) InvestTotal(c *gin.Context) {

	var err error

	userId, exist := c.Get("login_id")
	if !exist || userId == "" {
		c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1103, constant.ERROR_MESSAGE_1103))
		return
	}

	r := api.service.ModuleByName("MYSQLDB")
	if db, ok := r.(*module.MysqlDB); ok {
		result := make([]NodeInvest, 0)

		var nodes []*model.SysNodeContract

		// 管理员有最大的权限，直接看管理员
		var role model.SysRole
		err = db.Table(model.SysRoleTable).Where(map[string]interface{}{"id": 1}).Find(&role).Error
		if err != nil {
			go_logger.Logger.Error(err.Error())
			c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1001, constant.ERROR_MESSAGE_1001))
			return
		}

		selectDb := db.Table(model.SysNodeContractTable).Where(" node_primary_id in (?)", role.GetNodePerm())
		err = selectDb.Find(&nodes).Error
		if err != nil {
			go_logger.Logger.Error(err.Error())
			c.JSON(http.StatusOK, util.FailResponse(constant.ERROR_CODE_1001, constant.ERROR_MESSAGE_1001))
			return
		}

		for _, node := range nodes {
			result = append(result, NodeInvest{
				NodeId:     node.NodeId,
				NodeName:   node.NodeName,
				NodeInvest: node.StakingSum + node.DelegationSum,
			})
		}

		c.JSON(http.StatusOK, util.SuccessResponse(result))
		return
	}
}
